/*
 * Copyright 2023 Sweden Connect
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package se.swedenconnect.ca.service.base.ca.impl;

import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.util.List;

import org.bouncycastle.cert.X509CertificateHolder;

import lombok.Getter;
import lombok.Setter;
import se.swedenconnect.ca.engine.ca.issuer.CertificateIssuer;
import se.swedenconnect.ca.engine.ca.issuer.CertificateIssuerModel;
import se.swedenconnect.ca.engine.ca.issuer.impl.AbstractCAService;
import se.swedenconnect.ca.engine.ca.issuer.impl.BasicCertificateIssuer;
import se.swedenconnect.ca.engine.ca.models.cert.impl.DefaultCertificateModelBuilder;
import se.swedenconnect.ca.engine.ca.repository.CARepository;
import se.swedenconnect.ca.engine.revocation.crl.CRLIssuer;
import se.swedenconnect.ca.engine.revocation.crl.CRLIssuerModel;
import se.swedenconnect.ca.engine.revocation.crl.impl.SynchronizedCRLIssuer;
import se.swedenconnect.ca.engine.revocation.ocsp.OCSPResponder;
import se.swedenconnect.security.credential.PkiCredential;

/**
 * Abstract basic implementation of a CA based on the core CA ca-engine module.
 * <p>
 * This forms a basic model for providing a complete CA that includes a CA repository, a CRL issuer and optionally an
 * OCSP responder.
 */
public abstract class AbstractBasicCA extends AbstractCAService<DefaultCertificateModelBuilder> {

  /** The issuer functionality used to produce new certificates by the CA service */
  protected CertificateIssuer certificateIssuer;

  /** The CRL issuer used to issue CRL */
  protected CRLIssuer crlIssuer;

  /** The OCSP responder used to produce OCSP responses */
  @Setter
  protected OCSPResponder ocspResponder;

  /** The certificate for the OCSP response validation key */
  @Setter
  protected X509CertificateHolder ocspCertificate;

  /** List of CRL distribution points included in issued certificates */
  @Getter
  protected final List<String> crlDistributionPoints;

  /** The URL used to send OCSP requests to the OCSP responder in order to get an OCSP responder */
  @Setter
  protected String ocspResponderUrl;

  /**
   * Constructor for the abstract basic CA service.
   *
   * @param issuerCredential credentials for the CA issuing key
   * @param caRepository the repository used to store information about issued certificates
   * @param certIssuerModel the model defining fundamental rules for how certificates are issued
   * @param crlIssuerModel the model defining fundamental rules for issuing CRLs
   * @param crlDistributionPoints the URLs where CRLs generated by this CA will be published
   * @throws NoSuchAlgorithmException if a requested algorithm is not supported
   * @throws CertificateEncodingException error processing certificate data
   */
  public AbstractBasicCA(final PkiCredential issuerCredential, final CARepository caRepository,
    final CertificateIssuerModel certIssuerModel, final CRLIssuerModel crlIssuerModel,
    final List<String> crlDistributionPoints)
    throws NoSuchAlgorithmException, CertificateEncodingException {
    super(issuerCredential, caRepository);
    this.certificateIssuer = new BasicCertificateIssuer(certIssuerModel, issuerCredential);
    if (crlIssuerModel != null) {
      this.crlIssuer = new SynchronizedCRLIssuer(crlIssuerModel, caRepository.getCRLRevocationDataProvider(),
        issuerCredential);
    }
    this.crlDistributionPoints = crlDistributionPoints;
  }

  /** {@inheritDoc} */
  @Override
  public CertificateIssuer getCertificateIssuer() {
    return this.certificateIssuer;
  }

  /** {@inheritDoc} */
  @Override
  protected CRLIssuer getCrlIssuer() {
    return this.crlIssuer;
  }

  /** {@inheritDoc} */
  @Override
  public OCSPResponder getOCSPResponder() {
    return this.ocspResponder;
  }

  /** {@inheritDoc} */
  @Override
  public X509CertificateHolder getOCSPResponderCertificate() {
    return this.ocspCertificate;
  }

  /** {@inheritDoc} */
  @Override
  public String getCaAlgorithm() {
    return this.certificateIssuer.getCertificateIssuerModel().getAlgorithm();
  }

  /** {@inheritDoc} */
  @Override
  public List<String> getCrlDpURLs() {
    return this.crlDistributionPoints;
  }

  /** {@inheritDoc} */
  @Override
  public String getOCSPResponderURL() {
    return this.ocspResponderUrl;
  }

}
